import random
import sys
from time import sleep

import pygame

from settings import Settings
from game_stats import GameStats
from scoreboard import Scoreboard
from button import Button
from ship import Ship
from bullet import Bullet
from alien import Alien


class AlienInvasion:
    """管理游戏资产和行为的总体类。"""

    def __init__(self):
        """初始化游戏，并创建游戏资源"""
        # 设置pygame的默认字体为Arial
        pygame.init()
        pygame.font.init()
        self.last_alien_bullet_time = pygame.time.get_ticks()
        self.clock = pygame.time.Clock()  # Create a clock object to control the frame rate.
        self.settings = Settings()  # Create a Settings instance.
        self.screen = pygame.display.set_mode(
            (self.settings.screen_width, self.settings.screen_height), pygame.RESIZABLE)  # Create a window.
        pygame.display.set_caption("外星人入侵")  # Set the window title.
        self.stats = GameStats(self)  # Create a GameStats instance.
        self.sb = Scoreboard(self)  # Create a scoreboard.
        self.ship = Ship(self)  # Create a ship.
        self.aliens = pygame.sprite.Group()  # Create a group to store aliens.
        self._create_fleet()  # Create a fleet of aliens.
        self.game_active = False  # Start Alien Invasion in an inactive state.
        self.play_button = Button(self, "开始游戏")  # Create a play button.
        self.font = pygame.font.SysFont("方正舒体", 48)
        _start_game_button = self.font.render("开始游戏", True, (255, 0, 0), (255, 255, 255))
        _start_game_button_rect = _start_game_button.get_rect()
        _start_game_button_rect.center = (800, 400)

        self.screen.blit(_start_game_button, _start_game_button_rect)

        self.bg_image = pygame.image.load(self.settings.image_base_path + 'bg.jpg')  # 加载背景图片
        self.bg_image = pygame.transform.scale(self.bg_image,
                                               (self.settings.screen_width, self.settings.screen_height))  # 调整背景图片尺寸

        self.aliens_bullets = pygame.sprite.Group()  # Create a group to store alien bullets.
        self.ship_bullets = pygame.sprite.Group()  # Assign the bullets group to the ship.

        self.game_start_time = 0  # 记录游戏开始的时间

    def run_game(self):
        """开始游戏的主循环"""
        while True:
            self._check_events()  # 监视键盘和鼠标事件

            if self.game_active:
                self.ship.update()
                self._update_bullets()
                self._update_aliens_bullets()
                self._update_aliens()

                # 检查外星人子弹与飞船的碰撞
                if pygame.sprite.spritecollideany(self.ship, self.aliens_bullets):
                    self._ship_hit()

            self._update_screen()
            self.clock.tick(60)

            current_time = pygame.time.get_ticks()
            if self.game_start_time is not None and current_time - self.game_start_time >= 3000:  # 3秒后开始发射子弹
                if current_time - self.last_alien_bullet_time >= self.settings.alien_fire_rate:
                    for alien in self.aliens.sprites():
                        alien.fire_bullet()
                    self.last_alien_bullet_time = current_time

            self._remove_out_screen_bullet()

    def _check_events(self):
        """响应按键和鼠标事件"""
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                self.ship.check_keydown_events(event)
            elif event.type == pygame.KEYUP:
                self.ship.check_keyup_events(event)
            elif event.type == pygame.MOUSEBUTTONDOWN:
                mouse_pos = pygame.mouse.get_pos()
                self._check_play_button(mouse_pos)
            elif event.type == pygame.VIDEORESIZE:
                self.settings.screen_width = event.w
                self.settings.screen_height = event.h
                self.screen = pygame.display.set_mode(
                    (self.settings.screen_width, self.settings.screen_height), pygame.RESIZABLE)

    def _check_play_button(self, mouse_pos):
        """当玩家单击“玩”时，开始新游戏"""
        button_clicked = self.play_button.rect.collidepoint(mouse_pos)
        if button_clicked and not self.game_active:
            # 重置游戏设置
            self.settings.initialize_dynamic_settings()

            # 重置游戏统计信息。
            self.stats.reset_stats()
            self.sb.prep_score()
            self.sb.prep_level()
            self.sb.prep_ships()
            self.game_active = True

            # 清除所有剩余的子弹和外星人。
            self.aliens_bullets.empty()
            self.ship_bullets.empty()
            self.aliens.empty()

            # 创建一个新的舰队并使船居中
            self._create_fleet()
            self.ship.center_ship()

            # 隐藏鼠标光标。
            pygame.mouse.set_visible(False)

    def _update_bullets(self):
        """更新项目符号的位置并清除旧项目符号"""
        # 更新项目符号位置
        self.ship_bullets.update()

        # 扔掉已经消失的子弹
        for bullet in self.ship_bullets.copy():
            if bullet.rect.bottom <= 0:
                self.ship_bullets.remove(bullet)

        # 检查是否有子弹击中了外星人
        # 如果是这样，就删除相应的子弹和外星人
        self._check_bullet_alien_collisions()

        # 检查是否有外星人的子弹击中了飞船
        if pygame.sprite.spritecollideany(self.ship, self.aliens_bullets):
            self._ship_hit()

    def _update_aliens_bullets(self):
        """更新外星人子弹的位置并删除旧子弹"""
        self.aliens_bullets.update()

        for bullet in self.aliens_bullets.copy():
            if bullet.rect.bottom >= self.settings.screen_height:
                self.aliens_bullets.remove(bullet)

    def _check_bullet_alien_collisions(self):
        """应对子弹与外星人的碰撞"""
        # Remove any bullets and aliens that have collided(碰撞).
        collisions = pygame.sprite.groupcollide(
            self.ship_bullets, self.aliens, True, True)

        if collisions:
            for aliens in collisions.values():
                self.stats.score += self.settings.alien_points * len(aliens)
            self.sb.prep_score()
            self.sb.check_high_score()

        if not self.aliens:
            # Destroy existing bullets and create new fleet(舰队).
            self.ship_bullets.empty()
            self._create_fleet()
            self.settings.increase_speed()

            # Increase level.
            self.stats.level += 1
            self.sb.prep_level()

    def _ship_hit(self):
        """Respond to the ship being hit by an alien."""
        if self.stats.ships_left > 0:
            # Decrement ships_left, and update scoreboard.
            self.stats.ships_left -= 1
            # self.sb.prep_ships()

            # Get rid of any remaining bullets and aliens.
            self.ship_bullets.empty()
            self.aliens_bullets.empty()  # 清除所有剩余的外星人子弹
            self.aliens.empty()
            self.aliens_bullets.empty()  # 清除外星人的子弹

            # 创建一群新的外星人，并将飞船放到屏幕底部中央
            self._create_fleet()
            self.ship.center_ship()

            # Pause.
            sleep(0.5)
        else:
            self.game_active = False
            pygame.mouse.set_visible(True)

    def _update_aliens(self):
        """Check if the fleet is at an edge, then update positions."""
        self._check_fleet_edges()
        self.aliens.update()

        # Look for alien-ship collisions.
        if pygame.sprite.spritecollideany(self.ship, self.aliens):
            self._ship_hit()

        # Look for aliens hitting the bottom of the screen.
        self._check_aliens_bottom()

    def _check_aliens_bottom(self):
        """Check if any aliens have reached the bottom of the screen."""
        for alien in self.aliens.sprites():
            if alien.rect.bottom >= self.settings.screen_height:
                # Treat this the same as if the ship got hit.
                self._ship_hit()
                break

    def _create_fleet(self):
        """Create the fleet of aliens."""
        # Create an alien and keep adding aliens until there's no room left.
        # Spacing between aliens is one alien width and one alien height.
        alien = Alien(self)
        alien_width, alien_height = alien.rect.size

        for _ in range(self.settings.fleet_size):
            # Generate random x and y positions for each alien.
            x_position = random.randint(0, self.settings.screen_width - alien_width)
            # 在地图上半部分生成外星人
            y_position = random.randint(0, self.settings.screen_height // 2)
            self._create_alien(x_position, y_position)

    def _create_alien(self, x_position, y_position):
        """Create an alien and place it in the fleet."""
        new_alien = Alien(self)
        new_alien.x = x_position
        new_alien.rect.x = x_position
        new_alien.rect.y = y_position
        self.aliens.add(new_alien)

    def _check_fleet_edges(self):
        """Respond appropriately if any aliens have reached an edge."""
        for alien in self.aliens.sprites():
            if alien.check_edges():
                self._change_fleet_direction()
                break

    def _change_fleet_direction(self):
        """Drop the entire fleet and change the fleet's direction."""
        for alien in self.aliens.sprites():
            alien.rect.y += self.settings.fleet_drop_speed
        self.settings.fleet_direction *= -1

    def _update_screen(self):
        """Update images on the screen, and flip to the new screen."""
        self.screen.blit(self.bg_image, (0, 0))  # 在屏幕上绘制背景图片

        # Draw the bullets of ship.
        for bullet in self.ship_bullets.sprites():
            bullet.draw_bullet()
        # Draw the bullets of aliens.
        for bullet in self.aliens_bullets.sprites():
            bullet.draw_bullet()

        self.ship.blitme()
        self.aliens.draw(self.screen)

        # Draw the score information.
        self.sb.show_score()

        # Draw the play button if the game is inactive.
        if not self.game_active:
            self.play_button.draw_button()

        pygame.display.flip()

    def _remove_out_screen_bullet(self):
        """Remove bullets that have moved off the screen."""
        # 移除外星人的子弹
        for bullet in self.aliens_bullets.copy():
            if bullet.rect.bottom >= self.settings.screen_height:
                self.aliens_bullets.remove(bullet)

        # 移除玩家的子弹
        for bullet in self.ship_bullets.copy():
            if bullet.rect.bottom <= 0:
                self.ship_bullets.remove(bullet)
